package com.qfedu.lc.user.service.impl;


import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.druid.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qfedu.lc.common.config.RabbitKeyConfig;
import com.qfedu.lc.common.config.RedisKeyConfig;
import com.qfedu.lc.common.param.GrowthAdd;
import com.qfedu.lc.common.param.MqMsg;
import com.qfedu.lc.common.param.UserAdd;
import com.qfedu.lc.common.param.UserLogin;
import com.qfedu.lc.common.util.JwtUtil;
import com.qfedu.lc.common.vo.R;
import com.qfedu.lc.user.entity.Log;
import com.qfedu.lc.user.entity.User;
import com.qfedu.lc.user.mapper.LogMapper;
import com.qfedu.lc.user.mapper.UserMapper;
import com.qfedu.lc.user.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.http.HttpRequest;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 1.用户表 服务实现类
 * </p>
 *
 * @author wgz
 * @since 2024-01-24
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LogMapper logMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 1.判断参数是否为空
     * 2.判断验证码是否匹配
     * 3.判断手机号是否重复  账号是否重复
     * 4.密码加密 插入user表
     * 5.记录用户日志
     * 6.删除注册验证码
     * @param userAdd
     * @return
     */
    @Override
    public R register(UserAdd userAdd, HttpServletRequest httpRequest) {

        //  1.判断参数是否为空
        if (userAdd==null || StringUtils.isEmpty(userAdd.getPhone())
                ||StringUtils.isEmpty(userAdd.getAccount())
                ||StringUtils.isEmpty(userAdd.getCode())
                ||StringUtils.isEmpty(userAdd.getPassword())
        ){
            return R.fail("请检查参数");
        }

        // 2.判断验证码是否匹配

        String redisRegisterCode = stringRedisTemplate.opsForValue().get(RedisKeyConfig.SMS_RCODE+userAdd.getPhone());
        if (!userAdd.getCode().equals(redisRegisterCode)){
            return R.fail("请检查验证码");

        }
        // 3.判断手机号是否重复

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone",userAdd.getPhone());
        List<User> userList = userMapper.selectList(queryWrapper);

        if (userList!=null && userList.size()>0){
            return R.fail("该手机号已被注册");
        }

        //4.密码加密 插入user表
        // userAdd.getPassword() 密码需要加密  SecureUtil.sha256(SecureUtil.md5(userAdd.getPassword()))

        User user = new User(userAdd.getPhone(),userAdd.getAccount(),SecureUtil.sha256(SecureUtil.md5(userAdd.getPassword())),1,new Date());

        int num = userMapper.insert(user);
        if (num<=0){
            return R.fail("注册失败");
        }

//        5.记录用户日志
        Log log = new Log(user.getId(),"注册用户",httpRequest.getRemoteAddr(),userAdd.getPhone() + "注册账号",userAdd.getPhone(),new Date());
        logMapper.insert(log);

//        6.删除注册验证码
        stringRedisTemplate.delete(RedisKeyConfig.SMS_RCODE+userAdd.getPhone());

//        7.发送积分成长的消息
        GrowthAdd growthAdd = new GrowthAdd(user.getId(),"新用户注册",50);
        rabbitTemplate.convertAndSend("", RabbitKeyConfig.Q_USER_GROWTH,new MqMsg(IdUtil.getSnowflakeNextId(),5,growthAdd));


        return R.ok("恭喜你注册成功");
    }

    /**
     *
     * 1.判断参数是否为空
     * 2.判断账户是存在，可用
     * 3.验证用户 密码
     * 4.判断登录次数是否超过三次
     * 5.生成token
     * 6.存储token
     * 7.记录登录日志
     * 8.返回token
     * @param userLogin
     * @return
     */
    @Override
    public R loginPass(UserLogin userLogin,HttpServletRequest httpRequest) {

        //1.判断参数是否为空
        if (userLogin==null || StrUtil.hasEmpty(userLogin.getName(),userLogin.getPass())){
            return R.fail("请检查参数");
        }

//        2.判断账户是存在，可用
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account",userLogin.getName());
        List<User> userList = userMapper.selectList(queryWrapper);

        if (userList==null || userList.size()==0){
            return R.fail("该用户不存在");
        }
        // 第一个用户就是当前用户
        User user = userList.get(0);
        if (user.getStatus() !=1){
            return R.fail("该用户不可用");
        }

        //3.验证用户 密码  注意加密
        if(!user.getPassword().equals(SecureUtil.sha256(SecureUtil.md5(userLogin.getPass())))){
            return R.fail("账号 或者 密码 错误");
        }


        //  4.判断登录次数是否超过三次
        Set<String> keys = stringRedisTemplate.keys(RedisKeyConfig.LOGIN_UID_TOKEN + user.getId() + "*");
        if (keys!=null && keys.size()>=3){
            return R.fail("登录次数超过三次");
        }


        // 5.生成token
        String jwtToken = JwtUtil.createJwt(user.getId(), user.getAccount(), user.getPhone());

        // 6.存储token  redis存储token

        //  key id + token       可以计算该id 的次数  ==》  key:lc:uid:用户id:令牌   value 时间戳
        //  key   token         记录该token 对应的用户信息 ====> key:lc:token:令牌     value 用户对象信息

        stringRedisTemplate.opsForValue().set(RedisKeyConfig.LOGIN_UID_TOKEN+ user.getId()+":"+jwtToken,System.currentTimeMillis()+"",RedisKeyConfig.LOGIN_TOKEN_TIME, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(RedisKeyConfig.LOGIN_TOKEN+jwtToken,user,RedisKeyConfig.LOGIN_TOKEN_TIME, TimeUnit.SECONDS);

        // 6. 首次登录 发送积分成长的消息
        // 如何辨别用户首次登录  查看当前用户今天是否由登录日志，没有登录日志就是首次登录
        QueryWrapper<Log> logQueryWrapper = new QueryWrapper<>();

        logQueryWrapper.eq("user_id",user.getId());
        logQueryWrapper.eq("type","用户登录");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String date = simpleDateFormat.format(new Date());
        logQueryWrapper.gt("ctime",date);

        List<Log> logList = logMapper.selectList(logQueryWrapper);
        if (logList==null || logList.size()==0){ // 当前用户今日 首次登录
//            发送积分成长的消息
            GrowthAdd growthAdd = new GrowthAdd(user.getId(),"每日首次登录",2);
            rabbitTemplate.convertAndSend("", RabbitKeyConfig.Q_USER_GROWTH,new MqMsg(IdUtil.getSnowflakeNextId(),5,growthAdd));

        }


//        7.记录登录日志
        logMapper.insert(new Log(user.getId(),"用户登录",httpRequest.getRemoteAddr(),user.getAccount() + "账号登录",user.getPhone(),new Date()));



        // 8.返回token
        return R.ok(jwtToken);
    }

    @Override
    public R logout(String token) {

        // 1.根据token 得到用户信息
         User user = (User) redisTemplate.opsForValue().get(RedisKeyConfig.LOGIN_TOKEN + token);
        if (user==null){
            return R.fail("已经退出登录");
        }
        // 2.删除用户相关 token

        redisTemplate.delete(RedisKeyConfig.LOGIN_TOKEN + token);
        stringRedisTemplate.delete(RedisKeyConfig.LOGIN_UID_TOKEN+ user.getId()+":"+token);

        return R.ok("退出登录成功");
    }
}
